<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>

  <body>
    <div id="app">
      <p>{{ message }}</p>
      <input type="text" id="input" />
    </div>
    <script>
      //使用proxy操作的都是代理也就是p 可以想象成obj是一个明星  p代理是助手 基本上操作数据都是用代理
      let target = {
        value: 100,
        get() {
          console.log(this, "get");
        },
      };
      let p = new Proxy(target, {
        // receiver的作用是当被代理的对象有get那么这个this指向的就是target会绕过代理   因为receiver始终只想proxy  所以需要
        get: function (target, property, receiver) {
          // console.log(target, property, receiver, "get");
          return target[property];
        },
        set(target, property, value, receiver) {
          // console.log(target, this, "set");
          // console.log(property, "set-key");
          // console.log(value, "set-value");
          // console.log(receiver, "set");
          return (target[property] = value);
        },
        // target目标对象。prop需要检查是否存在的属性。
        has(target, prop) {
          // handler.has() 方法是针对 in 操作符的代理方法。
          return target[prop];
        },
      });

      // 没有响应式  因为把空对象赋值给p 它的地址不是proxy而是普通空对象
      p = Object.assign({}, { a: 3002 });
      // 有;  因为这个代码走的还是p的proxy的set
      p = Object.assign(p, { a: 3002 });

      console.log(p.a, target);
      // let { a } = p;
      // a = 100;
      // console.log(p, target);

      // let set = new Set();
      // const setProxy = new Proxy(set, {
      //   get(target, prop, receiver) {
      //     let val = target[prop];
      //     console.log(target, prop, "get");
      //     if (val instanceof Function) {
      //       return val.bind(target);
      //     }
      //     return val;
      //   },
      //   set(target, prop, value, receiver) {
      //     console.log(target, prop, value, "set");
      //     return (target[prop] = value);
      //   },
      // });
      // //   10.Proxy.html:55 Uncaught TypeError: Method Set.prototype.add called on incompatible receiver #<Set>
      // setProxy.add("5");

      // //   案例vue 数据驱动试图
      // function reactive(data) {
      //   return new Proxy(data, {
      //     get(target, key) {
      //       return target[key];
      //     },
      //     set(target, key, value) {
      //       target[key] = value;
      //       update();
      //     },
      //   });
      // }
      // function update() {
      //   const messageElement = document.querySelector("#app p");
      //   messageElement.textContent = data.message;

      //   const inputElement = document.querySelector("#input");
      //   inputElement.value = data.message;
      // }

      // const data = reactive({
      //   message: "双向绑定原理",
      // });

      // const inputElement = document.querySelector("#input");

      // inputElement.addEventListener("input", function (e) {
      //   data.message = e.target.value;
      // });
    </script>
  </body>
</html>

<!-- 你只要记住一句话：
receiver 就是：当你访问 proxy.x 时，getter 里面的 this 指向谁？→ 指向 receiver（通常就是 proxy）
下面我用一个你肯定能看懂的例子。
🔥 最直观的小例子（你一定能理解）
const obj = {
  name: "张三",
  get upperName() {
    return this.name.toUpperCase(); // 看到了 this.name 吗？
  }
}

const p = new Proxy(obj, {
  get(target, key, receiver) {
    return Reflect.get(target, key, receiver)
  }
})

console.log(p.upperName)

问题来了：

当执行 p.upperName 时，getter 中的 this.name 应该取谁的 name？

如果 this = obj（target）

如果 this = p（proxy）

这两个完全不同。

📌 为什么 receiver 很重要？

因为：

当我们访问 p.upperName 时，getter 里的 this 应该是 p，而不是 obj！

如果 this 是 obj，就变成：

obj.name.toUpperCase()


那你访问的是原对象，不是代理对象，proxy 就失效了。

🍉 看一个对比（你一下就懂）
❌ 不传 receiver → this 指向原对象（错误）
const p = new Proxy(obj, {
  get(target, key) {
    // ❌ Reflect.get 没给 receiver
    return Reflect.get(target, key)
  }
})
console.log(p.upperName)


getter 等价于：

obj.upperName()    // this === obj

✔ 传 receiver → this 指向代理对象（正确）
const p = new Proxy(obj, {
  get(target, key, receiver) {
    // ✔ 把 receiver 传给 Reflect.get
    return Reflect.get(target, key, receiver)
  }
})
console.log(p.upperName)


getter 内部变成：

p.name.toUpperCase()   // this === p


成功走代理，也可以触发响应式。

🧠 用一句更简单的话解释
receiver 就是 getter 里 this 应该指向谁。

你用 proxy 去访问，就应该把 this 也指向 proxy，而不是 target -->
